package com.ict.txmsv2.services.impl;

import com.ict.txmsv2.model.*;
import com.ict.txmsv2.services.*;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

/**
 * @Author lht
 * @date 2021/9/24 - 18:01
 * @description: Word文档的导入导出实现类
 */
@Service
@Slf4j
public class WordInfoServiceImpl implements WordInfoService {

    @Resource
    private ExecutorService executorService;
    @Resource
    private CompetitionPrizeService competitionPrizeService;
    @Resource
    private ProjectEstablishService projectEstablishService;
    @Resource
    private IPatentService patentService;
    @Resource
    private IPapersService papersService;
    @Resource
    private IAchievementService achievementService;
    @Resource
    private IInnovationService iInnovationService;
    @Resource
    private ICertificatesService certificatesService;
    @Resource
    private ICompetitionTrainingService competitionTrainingService;
    @Resource
    private ICompanyService companyService;

    private static final int TABLE_NUM = 9;



    @Override
    public boolean getWordTemplate(ServletOutputStream outputStream) {
        byte[] bytes = new byte[256];
        //获取Word模板，模板存放路径在项目的resources目录下
        InputStream ins = this.getClass().getResourceAsStream("/templates/template1.docx");
        try {
            while (true) {
                int read = ins.read(bytes);
                if (read != -1) {
                    outputStream.write(bytes, 0, read);
                }else {
                    break;
                }
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * TODO: 事务有问题，无法做到一个出错全部回滚
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean writeInfo2DB(List<Queue<String>> list) throws Exception{
        WordInfoServiceImpl wordInfoService = (WordInfoServiceImpl) AopContext.currentProxy();
        CompletableFuture<Boolean>[] tasks = new CompletableFuture[list.size()];
        for (int i = 0; i < tasks.length; i++) {
            int finalI = i;
            Queue<String> queue = list.get(finalI);
            tasks[i] = CompletableFuture.supplyAsync(() -> {
                switch (finalI) {
                    case 0: return wordInfoService.saveCompetitionPrize(queue);
                    case 1: return wordInfoService.saveProjectEstablish(queue);
                    case 2: return wordInfoService.savePatent(queue);
                    case 3: return wordInfoService.savePapers(queue);
                    case 4: return wordInfoService.saveInnovation(queue);
                    case 5: return wordInfoService.saveCompany(queue);
                    case 6: return wordInfoService.saveCertificates(queue);
                    case 7: return wordInfoService.saveAchievement(queue);
                    case 8: return wordInfoService.saveCompetitionTraining(queue);
                    default: return false;
                }
            }, executorService);
        }
        CompletableFuture.allOf(tasks).get();
        for (CompletableFuture<Boolean> task : tasks) {
            try {
                if (!task.get()) {
                    return false;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * 保存竞赛奖励信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return 是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCompetitionPrize(Queue<String> q) {
        List<CompetitionPrize> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            CompetitionPrize competitionPrize = new CompetitionPrize();
            competitionPrize.setName(q.poll());
            competitionPrize.setLevel(q.poll());
            competitionPrize.setPrize(q.poll());
            competitionPrize.setMembers(q.poll());
            competitionPrize.setTeacher(q.poll());
            competitionPrize.setTime(q.poll());
            list.add(competitionPrize);
        }
        return competitionPrizeService.batchSave(list);
    }

    /**
     * 保存课题立项信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return 是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveProjectEstablish(Queue<String> q) {
        List<ProjectEstablish> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            ProjectEstablish establish = new ProjectEstablish();
            establish.setName(q.poll());
            establish.setLevel(q.poll());
            establish.setStartTime(q.poll());
            establish.setEndTime(q.poll());
            establish.setMembers(q.poll());
            establish.setTeacher(q.poll());
            list.add(establish);
        }
        return projectEstablishService.batchSave(list);
    }

    /**
     * 保存专利或软件著作权
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean savePatent(Queue<String> q) {
        List<Patent> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            Patent patent = new Patent();
            patent.setName(q.poll());
            patent.setCategories(q.poll());
            patent.setStartTime(q.poll());
            patent.setEndTime(q.poll());
            patent.setMembers(q.poll());
            patent.setTeacher(q.poll());
            list.add(patent);
        }
        return patentService.saveBatch(list);
    }

    /**
     * 保存发表论文信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean savePapers(Queue<String> q) {
        List<Papers> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            Papers papers = new Papers();
            papers.setTitle(q.poll());
            papers.setName(q.poll());
            papers.setQiJuan(q.poll());
            papers.setPages(q.poll());
            papers.setAuthor(q.poll());
            papers.setTeacher(q.poll());
            list.add(papers);
        }
        return papersService.saveBatch(list);
    }

    /**
     * 保存学生考取资格证信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCertificates(Queue<String> q) {
        List<Certificates> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            Certificates certificates = new Certificates();
            certificates.setCertificateName(q.poll());
            certificates.setLevel(q.poll());
            certificates.setStuName(q.poll());
            certificates.setGrade(q.poll());
            certificates.setTime(q.poll());
            certificates.setTeacher(q.poll());
            list.add(certificates);
        }
        return certificatesService.saveBatch(list);
    }

    /**
     * 保存学生创新创业团队奖励信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveInnovation(Queue<String> q) {
        List<Innovation> list = new ArrayList<>(q.size() / 6);
        while (!q.isEmpty()) {
            Innovation innovation = new Innovation();
            innovation.setTeamName(q.poll());
            innovation.setCategories(q.poll());
            innovation.setTime(q.poll());
            innovation.setRewards(q.poll());
            innovation.setMembers(q.poll());
            innovation.setTeacher(q.poll());
            list.add(innovation);
        }
        return iInnovationService.saveBatch(list);
    }

    /**
     * 保存就业考研情况信息
     * @param q 数据队列，其中每个String都是一个字段值 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAchievement(Queue<String> q) {
        List<Achievement> list = new ArrayList<>(q.size() / 5);
        while (!q.isEmpty()) {
            Achievement achievement = new Achievement();
            achievement.setGrade(q.poll());
            achievement.setStuName(q.poll());
            achievement.setUnit(q.poll());
            achievement.setPosition(q.poll());
            achievement.setSalary(q.poll());
            list.add(achievement);
        }
        return achievementService.saveBatch(list);
    }

    /**
     * 保存学生注册公司信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCompany(Queue<String> q) {
        List<Company> list = new ArrayList<>(q.size() / 4);
        while (!q.isEmpty()) {
            Company company = new Company();
            company.setCompanyName(q.poll());
            company.setGrade(q.poll());
            company.setStuName(q.poll());
            company.setBusiness(q.poll());
            list.add(company);
        }
        return companyService.saveBatch(list);
    }

    /**
     * 保存工作室承担的校级竞赛项目及其他培训信息
     * @param q 数据队列，其中每个String都是一个字段值
     * @return  是否保存成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCompetitionTraining(Queue<String> q) {
        List<CompetitionTraining> list = new ArrayList<>(q.size() / 5);
        while (!q.isEmpty()) {
            CompetitionTraining competitionTraining = new CompetitionTraining();
            competitionTraining.setContent(q.poll());
            competitionTraining.setLevel(q.poll());
            competitionTraining.setTime(q.poll());
            competitionTraining.setParticipate(q.poll());
            competitionTraining.setTeacher(q.poll());
            list.add(competitionTraining);
        }
        return competitionTrainingService.saveBatch(list);
    }

    @Override
    public boolean downLoadWordDoc(ServletOutputStream outputStream) {
        //获取Word模板，模板存放路径在项目的resources目录下
        InputStream ins = this.getClass().getResourceAsStream("/templates/template1.docx");
        //注册xdoc report实例并加载FreeMarker模板引擎
        IXDocReport report = null;
        //创建xdocreport上下文对象
        final IContext context;
        CompletableFuture<List>[] tasks = new CompletableFuture[TABLE_NUM];
        try {
            report = XDocReportRegistry.getRegistry().loadReport(ins, TemplateEngineKind.Freemarker);
            context = report.createContext();
            //创建字段元数据
            FieldsMetadata fm = report.createFieldsMetadata();
            //Word模板中的表格数据对应的集合类型
            fm.load("Cp", CompetitionPrize.class, true);
            fm.load("Pe", ProjectEstablish.class, true);
            fm.load("Pt", Patent.class, true);
            fm.load("Pp", Papers.class, true);
            fm.load("In", Innovation.class, true);
            fm.load("Cpy", Company.class, true);
            fm.load("Ctf", Certificates.class, true);
            fm.load("Ach", Achievement.class, true);
            fm.load("Ctt", CompetitionTraining.class, true);
            for (int i = 0; i < TABLE_NUM; i++) {
                int finalI = i;
                tasks[i] = CompletableFuture.supplyAsync(() -> {
                    switch (finalI) {
                        case 0: return handleCompetitionPrizeList();
                        case 1: return handleProjectEstablishList();
                        case 2: return handlePatentList();
                        case 3: return handlePapersList();
                        case 4: return handleInnovationList();
                        case 5: return handleCompanyList();
                        case 6: return handleCertificatesList();
                        case 7: return handleAchievementList();
                        case 8: return handleCompetitionTrainingList();
                        default: return null;
                    }
                }, executorService);
            }
            CompletableFuture.allOf(tasks).get();
            for (int i = 0; i < TABLE_NUM; i++) {
                List list = tasks[i].get();
                switch (i) {
                    case 0: context.put("Cp", list); break;
                    case 1: context.put("Pe", list); break;
                    case 2: context.put("Pt", list); break;
                    case 3: context.put("Pp", list); break;
                    case 4: context.put("In", list); break;
                    case 5: context.put("Cpy", list); break;
                    case 6: context.put("Ctf", list); break;
                    case 7: context.put("Ach", list); break;
                    case 8: context.put("Ctt", list); break;
                    default: break;
                }
            }
            report.process(context, outputStream);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private List<CompetitionTraining> handleCompetitionTrainingList() {
        List<CompetitionTraining> list = competitionTrainingService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Achievement> handleAchievementList() {
        List<Achievement> list = achievementService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Certificates> handleCertificatesList() {
        List<Certificates> list = certificatesService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Company> handleCompanyList() {
        List<Company> list = companyService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Innovation> handleInnovationList() {
        List<Innovation> list = iInnovationService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Papers> handlePapersList() {
        List<Papers> list = papersService.list();
        for (int i = 1; i <= list.size(); i++) {
            list.get(i - 1).setId(i);
        }
        return list;
    }

    private List<Patent> handlePatentList() {
        List<Patent> patentList = patentService.list();
        for (int i = 1; i <= patentList.size(); i++) {
            patentList.get(i - 1).setId(i);
        }
        return patentList;
    }

    private List<ProjectEstablish> handleProjectEstablishList() {
        List<ProjectEstablish> projectEstablishInfo = projectEstablishService.getAllProjectEstablishInfo();
        for (int i = 1; i <= projectEstablishInfo.size(); i++) {
            projectEstablishInfo.get(i - 1).setId(i);
        }
        return projectEstablishInfo;
    }

    private List<CompetitionPrize> handleCompetitionPrizeList() {
        List<CompetitionPrize> competitionPrizeList = competitionPrizeService.getAllCompetitionPrizeInfo();
        for (int i = 1; i <= competitionPrizeList.size(); i++) {
            competitionPrizeList.get(i - 1).setId(i);
        }
        return competitionPrizeList;
    }


}
